﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Text;
using OpenLS.Drawing;

namespace OpenLS.Chart.UI.Internals
{
    class PieSeriesViewModel : ShapedViewModel
    {
        private readonly PieSeries _pieSeries;

        public PieSeriesViewModel(PieSeries pieSeries)
            : base(pieSeries)
        {
            Contract.Requires(pieSeries != null);
            _pieSeries = pieSeries;
            WeakEventHelper.AddWeakPropertyChanged(PieSeries, onPieSeriesPropertyChanged);
            if (PieSeries.Values != null)
                WeakEventHelper.AddWeakValueChanged(PieSeries, onPieSeriesChanged);
            INotifyValueChanged notifyValueChanged = pieSeries.Categories as INotifyValueChanged;
            if (notifyValueChanged != null)
                Chart.WeakEventHelper.AddWeakValueChanged(notifyValueChanged, onPieSeriesChanged);
        }

        private void onPieSeriesChanged(object sender, EventArgs args)
        {
            NotifyPropertyChanged("Values");
        }

        private void onPieSeriesPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            switch (e.PropertyName)
            {
                case "Categories":
                    NotifyPropertyChanged("Values");
                    break;
                case "Values":
                    {
                        NotifyPropertyChanged("Values");
                    }
                    break;
                default:
                    Debug.WriteLine("not handled " + e.PropertyName);
                    break;
            }
        }

        public IEnumerable<PieSeriesValue> Values
        {
            get
            {
                IEnumerator<object> categories = PieSeries.Categories != null ? PieSeries.Categories.Values.GetEnumerator() : null;
                {
                    int index = 0;
                    object category = null;
                    foreach (var v in PieSeries.Values.NumericValues)
                    {
                        if (categories != null)
                        {
                            if (categories.MoveNext())
                            {
                                category = categories.Current;
                                if (category is StringValue)
                                    category = ((StringValue) category).Value;
                            }
                            else
                            {
                                category = v.Value;
                                categories = null;
                            }
                        }
                        else
                            category = v.Value;
                        yield return new PieSeriesValue(category, v.Value, index++);
                    }
                }
            }
        }

        private PieSeries PieSeries
        {
            get
            {
                Contract.Ensures(Contract.Result<PieSeries>() != null);
                return _pieSeries;
            }
        }

        public class PieSeriesValue
        {
            private readonly object _category;
            private readonly double _value;
            private int _index;

            public PieSeriesValue(object category, double value, int index)
            {
                Contract.Requires(category != null);
                Contract.Requires(!(category is StringValue));
                _index = index;
                _category = category;
                _value = value;
            }
            public object Text { get { return this; } } //\\hack
            public string ActualValue { get { return _category.ToString(); } }
            public ShapeProperties ShapeProperties { get { return null; } }
            public int Index { get { return _index; } }

            public object Category
            {
                get { return _category; }
            }

            public double Value
            {
                get { return _value; }
            }
        }
    }
}
